/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.r.analysis.grr;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import com.intelligent.ispc.common.utils.ResourceBundleUtils;
import com.intelligent.ispc.common.utils.StringUtils;
import com.intelligent.ispc.constant.AppConstant;
import com.intelligent.ispc.core.dto.GrrAnalysisDataDto;
import com.intelligent.ispc.core.dto.GrrAnovaDto;
import com.intelligent.ispc.core.dto.GrrParamDto;
import com.intelligent.ispc.core.dto.GrrSourceDto;
import com.intelligent.ispc.r.analysis.RCommand;
import com.intelligent.ispc.r.utils.REnConnector;
import com.intelligent.ispc.r.utils.RUtils;
import org.rosuda.JRI.REXP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 2015/12/10.
 */
public class GrrAnovaAndSourceCommand implements RCommand {
    private static Logger logger = LoggerFactory.getLogger(GrrAnovaAndSourceCommand.class);

    private String scriptPath = "";
    private GrrParamDto grrParamDto;
    private GrrConfiguration configuration;
    private GrrAnalysisDataDto analysisParam;
    private Map<String, Object> resultData = Maps.newHashMap();

    private double operator = 0D;
    private double parts = 0D;
    private double trial = 0D;
    private double sigma = 0D;

    private String grrName;
    private String itemName;

    /**
     * @param scriptPath the file path
     */
    public GrrAnovaAndSourceCommand(String scriptPath) {
        this.scriptPath = scriptPath;
    }

    protected void buildScript() {
        try {
            REnConnector con = RUtils.getInstance().getConnector();


            operator = Double.parseDouble(grrParamDto.getOperatorValue());
            parts = Double.parseDouble(grrParamDto.getPartValue());
            trial = Double.parseDouble(grrParamDto.getTrialValue());
            sigma = Double.parseDouble(grrParamDto.getSigma());

            grrName = grrParamDto.getGrrName();
            itemName = grrParamDto.getItemName();

            String dataSettings = getDataSettings(analysisParam, con);

            con.setInput("bitNum", grrParamDto.getDigitNum());

            con.setInput("build", dataSettings);
            con.setInput("funName", "grr.buildAnovaAndSource(items)");
            con.execEval("source(\"" + scriptPath + "\")");

            this.buildResultData(analysisParam, con);
            while (con.isActive()) {
                con.disconnect();
            }
            RUtils.getSemaphore().release();

        } catch (Exception ex) {
            throw new ApplicationException(ExceptionMessages.ERR_20001, ResourceBundleUtils.getString(ExceptionMessages.EXCEPTION_GLOBAL_SYSTEM));
        }
    }


    private String getDataSettings(GrrAnalysisDataDto dto, REnConnector con) {
        StringBuilder sb = new StringBuilder();
        sb.append("items <- grr.buildData(");

        double usl = Double.valueOf(dto.getUsl());
        double lsl = Double.valueOf(dto.getLsl());
        double tole = Double.valueOf(AppConstant.GLOBAL_NAN);
        if (!Double.isNaN(usl) && !Double.isNaN(lsl)) {
            tole = usl - lsl;
        }
        con.setInput("x", dto.getAnalysisData());
        sb.append("list(data=x,")
                .append("appraisers=" + operator + ",")
                .append("parts=" + parts + ",")
                .append("trials=" + trial + ",")
                .append("sigma=" + sigma + ",")
                .append("tole=" + tole + ")")
                .append(")");

        return sb.toString();
    }

    private void buildResultData(GrrAnalysisDataDto dto, REnConnector con) {
        REXP expression = con.getEval("anovaValue");
        double[][] anovaValue = null;
        if (expression != null) {
            anovaValue = expression.asDoubleMatrix();
        }
        expression = con.getEval("sourceValue");

        double[][] sourceValue = null;
        if (expression != null) {
            sourceValue = expression.asDoubleMatrix();
        }

        List<GrrAnovaDto> anovaList = Lists.newArrayList();
        String[] anovaKeyValue = new String[]{AppConstant.GRR_ANOVA_APPRAISERS, AppConstant.GRR_ANOVA_PARTS, AppConstant.GRR_ANOVA_APPRAISERS_AND_PARTS, AppConstant.GRR_ANOVA_GAGE, AppConstant.GRR_ANOVA_TOTAL};
        if (anovaValue != null) {
            for (int i = 0; i < anovaValue.length; i++) {
                GrrAnovaDto anovaDto = new GrrAnovaDto();
                //anovaDto.setProjectId(projectId);
                anovaDto.setGrrName(grrName);
                //anovaDto.setStationAndSlot(stationAndSlot);
                anovaDto.setItemName(itemName);

                anovaDto.setKeyValue(anovaKeyValue[i]);
                anovaDto.setDfValue(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(anovaValue[i][0] + "")) ? "-" : configuration.getDataValue(anovaValue[i][0] + ""))));
                anovaDto.setSsValue(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(anovaValue[i][1] + "")) ? "-" : configuration.getDataValue(anovaValue[i][1] + ""))));
                anovaDto.setMsValue(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(anovaValue[i][2] + "")) ? "-" : configuration.getDataValue(anovaValue[i][2] + ""))));
                anovaDto.setfValue(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(anovaValue[i][3] + "")) ? "-" : configuration.getDataValue(anovaValue[i][3] + ""))));
                anovaDto.setProbFValue(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(anovaValue[i][4] + "")) ? "-" : configuration.getDataValue(anovaValue[i][4] + ""))));
                anovaList.add(anovaDto);
            }
        }

        List<GrrSourceDto> sourceList = Lists.newArrayList();
        String[] sourceKeyValue = new String[]{AppConstant.GRR_SOURCE_REPEATABILITY, AppConstant.GRR_SOURCE_REPRODUCIBILITY, AppConstant.GRR_SOURCE_APPRAISERS,
                AppConstant.GRR_SOURCE_APPRAISERS_AND_PARTS, AppConstant.GRR_SOURCE_GAGE_RR, AppConstant.GRR_SOURCE_PART, AppConstant.GRR_SOURCE_TOTAL};
        String grrSigma = null;
        String partSigma = null;
        if (sourceValue != null) {
            for (int i = 0; i < sourceValue.length; i++) {
                GrrSourceDto sourceDto = new GrrSourceDto();
                //sourceDto.setProjectId(projectId);
                sourceDto.setGrrName(grrName);
                //sourceDto.setStationAndSlot(stationAndSlot);
                sourceDto.setItemName(itemName);
                sourceDto.setKeyValue(sourceKeyValue[i]);
                sourceDto.setVariation(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][0] + "")) ? "-" : configuration.getDataValue(sourceValue[i][0] + ""))));
                sourceDto.setSigma(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][1] + "")) ? "-" : configuration.getDataValue(sourceValue[i][1] + ""))));
                sourceDto.setxSigma(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][2] + "")) ? "-" : configuration.getDataValue(sourceValue[i][2] + ""))));
                sourceDto.setContribution(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][3] + "")) ? "-" : configuration.getDataValue(sourceValue[i][3] + ""))));
                sourceDto.setTotalVariation(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][4] + "")) ? "-" : configuration.getDataValue(sourceValue[i][4] + ""))));
                sourceDto.setTolerance(StringUtils.formatBigDecimal(String.valueOf(Double.isNaN(configuration.getDataValue(sourceValue[i][5] + "")) ? "-" : configuration.getDataValue(sourceValue[i][5] + ""))));
                if (i == 4 && StringUtils.isNumeric(sourceDto.getTolerance())) {
                    sourceDto.setResult(configuration.getLevelType(configuration.getDataValue(sourceValue[i][5] + "")));
                }
                if (sourceDto.getKeyValue().equals(AppConstant.GRR_SOURCE_GAGE_RR)) {
                    grrSigma = sourceDto.getSigma();
                }
                if (sourceDto.getKeyValue().equals(AppConstant.GRR_SOURCE_PART)) {
                    partSigma = sourceDto.getSigma();
                }
                if (i == sourceValue.length - 1) {
                    sourceDto.setDistincCategories(getDistinctGategories(partSigma, grrSigma));
                }
                sourceList.add(sourceDto);
            }
        }

        this.resultData.put(AppConstant.GRR_ANOVA_VALUE, anovaList);
        this.resultData.put(AppConstant.GRR_SOURCE_VALUE, sourceList);
    }

    @Override
    public void execute() {
        buildScript();
    }


    public GrrAnalysisDataDto getAnalysisParam() {
        return analysisParam;
    }

    public void setAnalysisParam(GrrAnalysisDataDto analysisParam) {
        this.analysisParam = analysisParam;
    }

    public Map<String, Object> getResultData() {
        return resultData;
    }

    public void setResultData(Map<String, Object> resultData) {
        this.resultData = resultData;
    }

    public GrrParamDto getGrrParamDto() {
        return grrParamDto;
    }

    public void setGrrParamDto(GrrParamDto grrParamDto) {
        this.grrParamDto = grrParamDto;
    }

    public GrrConfiguration getConfiguration() {
        return configuration;
    }

    public void setConfiguration(GrrConfiguration configuration) {
        this.configuration = configuration;
    }

    private String getDistinctGategories(String partSigma, String grrSigma) {
        if (partSigma == null || grrSigma == null) {
            return "-";
        }

        if (grrSigma != null && (grrSigma.equals("-") || partSigma.equals("-") || Double.valueOf(grrSigma) == 0D)) {
            return "-";
        }

        Double disinctGategories = (Double.valueOf(partSigma) / Double.valueOf(grrSigma)) * 1.41;
        return String.valueOf((int) Math.floor(disinctGategories));
    }
}
